from rest_framework import serializers
import re, logging
from django_redis import get_redis_connection
from rest_framework.relations import StringRelatedField
from rest_framework_jwt.settings import api_settings


from .models import User, Address
from celery_tasks.email.tasks import send_verify_email
from goods.models import Goods, SKU

logger = logging.getLogger("django")
# 创建添加用户序列化器
class CreateUserSerializer(serializers.ModelSerializer):
    # 添加反序列化验证时需要的字段
    password2 = serializers.CharField(label='确认密码', write_only=True)
    sms_code = serializers.CharField(label='短信验证码', write_only=True)
    allow = serializers.CharField(label='同意协议', write_only=True)
    # 创建token 使用read_only=true 不能修改token,只能序列化
    token = serializers.CharField(label='登录状态token', read_only=True)  # 增加token字段
    # 序列化器 Meta 必须大写
    class Meta:
        # 映射对象
        model = User
        #　需要映射的字段
        fields = ['id', 'username', 'password', 'password2', 'mobile', 'sms_code', 'allow', 'token']
        # 修改字段的验证条件
        extra_kwargs = {
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的用户名',
                    'max_length': '仅允许5-20个字符的用户名',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }
    # 验证手机号码
    def validated_mobile(self, value):
        if not re.match(r"1[3-9]\d{9}", value):
            raise serializers.ValidationError("手机号码错误！")
        return value
    # 验证用户是否确认协议
    def validated_allow(self, value):
        if value != "True":
            raise serializers.ValidationError("请同意用户协议")
        return value

    def validate(self, attrs):
        # 判断两次密码是否一致
        if attrs["password"] != attrs["password2"]:
            raise serializers.ValidationError("密码输入不一致")

        # 验证验证码是否正确
        conn = get_redis_connection("verify_codes")
        real_sms_code = conn.get("sms_code_%s" % attrs["mobile"])
        if real_sms_code is None:
            raise serializers.ValidationError("请输入短信验证码!")
        # 需要注意redis取出来后需要decode()
        if real_sms_code.decode() != attrs["sms_code"]:
            raise serializers.ValidationError("请输入正确的短信验证码！")
        return attrs

    def create(self, validated_data):
        # 删除不需要的字段
        del validated_data["password2"]
        del validated_data["sms_code"]
        del validated_data["allow"]
        # 创建对象
        user = User(**validated_data)
        #取出密码，进行加密
        user.set_password(user.password)
        user.save()


        # 补充生成记录登录状态的token
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        user.token = token

        logger.info(user.token)

        return user



# 创建用户中心序列化器
class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        #　要映射的模型
        model = User
        fields = ["id", "username", "mobile", "email", "email_active"]


class EmailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "email"]
        extra_kwargs = {
            "email":{
                "required": True
            }
        }
    #　验证下邮箱格式
    def validate_email(self, value):
        if not re.match(r"^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$", value):
            raise serializers.ValidationError("邮箱输入错误")
        return value

    # 更新邮箱
    def update(self, instance, validated_data):
        instance.email = validated_data.get("email")
        instance.save()
        # 验证链接 verify_url
        verify_url = instance.generate_email_verify_url()
        # 发送邮件
        send_verify_email.delay(validated_data.get("email"), verify_url)

        return instance


class UserAddressSerializer(serializers.ModelSerializer):
    '''
    用户地址序列化器
    '''
    province = StringRelatedField(label="省", read_only=True)
    city = StringRelatedField(label="市", read_only=True)
    district = StringRelatedField(label="县区", read_only=True)
    province_id = serializers.IntegerField(label="省ID", required=True)
    city_id = serializers.IntegerField(label="市ID", required=True)
    district_id = serializers.IntegerField(label="县区ID", required=True)

    class Meta:
        model = Address
        exclude = ["user", "is_deleted", "create_time", "update_time"]

    def validate_mobile(self, value):
        if not re.match(r"^1[3-9]\d{9}$", value):
            return serializers.ValidationError("手机号格式错误")
        return value

    # 新增收货地址
    def create(self, validated_data):

        user = self.context["request"].user
        validated_data["user"] = user
        return Address.objects.create(**validated_data)


class AddressTitleSerializer(serializers.ModelSerializer):
    """
    地址标题
    """
    class Meta:
        model = Address
        fields = ('title',)



class UserBrowseHistorySerializer(serializers.Serializer):
    """反序列化用户浏览记录"""
    sku_id = serializers.IntegerField(label='商品SKU编码', min_value=1)

    def validate_sku_id(self, value):
        """单独到sku_id进行额外校验"""
        try:
            SKU.objects.get(id=value)
        except SKU.DoesNotExist:
            raise serializers.ValidationError('sku id 不存在')

        # 能走到这里说明sku_id 商品存在
        return value

    def create(self, validated_data):
        """重写此方法就让把我们的浏览记录存到redis,不存到数据库"""

        # 取出sku_id
        sku_id = validated_data.get('sku_id')
        # 获取用户的id动态拼接当redis数据key
        user_id = self.context.get('request').user.id

        # 创建redis连接
        redis_conn = get_redis_connection('history')
        # 创建管道
        pl = redis_conn.pipeline()
        # 去重
        pl.lrem('history_%s' % user_id, 0, sku_id)

        # 添加
        pl.lpush('history_%s' % user_id, sku_id)

        # 截取
        pl.ltrim('history_%s' % user_id, 0, 4)

        # 执行管道
        pl.execute()

        return validated_data









